package fr.mehfile.api.update;

import fr.mehfile.api.database.DataBase;
import fr.mehfile.api.parser.UpdateData;
import fr.mehfile.api.update.settings.UpdateManagerSettings;
import fr.mehfile.api.update.tasks.DatabaseUpdateTask;
import fr.mehfile.api.update.tasks.DownloadImagesTask;
import fr.mehfile.api.update.tasks.ParseXMLTask;
import fr.mehfile.api.update.tasks.ReadXMLTask;
import fr.mehfile.api.update.tasks.SettingsUpdateTask;
import fr.mehfile.api.update.tasks.UpdateDataValidatorTask;
import fr.mehfile.view.utils.Constants;
import fr.mehfile.view.utils.Utils;

import android.content.Context;

import java.io.InputStream;

public class UpdateTask implements TasksListener {

    private static final String TAG = "UpdateTask";
    private Tasks currentTask;
    private Context context;
    private DataBase database;
    private UpdateManagerSettings updateManagerSettings;
    private static UpdateTask singleton;
    private UpdateListener listener;

    private UpdateTask(Context context) {

        this.context = context;
        // instanciation de la classe qui sauvegardera des donnees unique de l'application comme l'url du seveur, la version du xml , etc...
        updateManagerSettings = new UpdateManagerSettings(context);
    }
    
    /**
     * saugegarde de l'observateur pour etre prevenu du statut de la mise a jour des donnee
     * @param UpdateListener observateur
     */
    public void addListener(UpdateListener listener){
       this.listener=listener;
    }
    
    /**
     * Suppresion de l'observateur
     * @param UpdateListener observateur
     */
    public void removeListener(UpdateListener listener){
        this.listener=null;
    }

    /**
     * @return UpdateManagerSettings, classe qui sauvegardera des donnees unique de l'application
     */
    public UpdateManagerSettings getSettings() {
        return updateManagerSettings;
    }

    /**
     * @param context
     * @return UpdateTask instantiation singleton de la classe
     */
    public static UpdateTask getInstance(Context context) {
        if (singleton == null)
            singleton = new UpdateTask(context);
        return singleton;
    }

    /**
     * @param database base de donnee qui sauvegardera les donnes de l'application
     */
    private void setDatabase(DataBase database) {
        this.database = database;
    }

    /* ************************* */
    /*       Launch tasks        */
    /* ************************* */

   
    /** instanciation de la base de donne et lancement de la mise a jour des donnee
     * @param context
     */
    public  void launchMainTask(Context context) {
        
        singleton.setDatabase(DataBase.getInstance(context));

        singleton.launchReadXML();

    }

    private void launchReadXML() {
    	// recuperation de l'url  du serveur a partir des preferences. Par defaut c'est l'url stockee dans les constantes
        updateManagerSettings.getUrlServer();
      
        // lancement de le tache telechargement du fichier xml de mise a jour des donnees
        currentTask = new ReadXMLTask(context, Constants.SERVER_URL, this);
        currentTask.execute((Void) null);

    }

    private void launchParseXML(InputStream xml) {
        currentTask = new ParseXMLTask(context, this, xml);
        currentTask.execute((Void) null);
    }

    private void launchValidatorTask(UpdateData updateDataBaseResults) {
        
        currentTask = new UpdateDataValidatorTask(this, updateDataBaseResults,updateManagerSettings, context);
        currentTask.execute((Void) null);
    }

    private void launchDatabaseUpdate(UpdateData updateData) {

        currentTask = new DatabaseUpdateTask(context, this, updateData, database);
        currentTask.execute((Void) null);
    }

    private void launchSettingsUpdate(UpdateData updateData) {

        currentTask = new SettingsUpdateTask(context, this, updateManagerSettings, updateData);
        currentTask.execute((Void) null);
    }

    private void launchDownloadImages()
    {
        currentTask = new DownloadImagesTask(context, this,database);
        currentTask.execute((Void)null);
    }
    
    /* ************************* */
    /*       Completed tasks     */
    /* ************************* */

    private void onReadXMLTaskComplete(InputStream response) {
        Utils.debugger.logDebug(TAG, "ReadXMLTask Complete, launch ParseXMLTask");
        launchParseXML(response);

    }

    private void onParseXMLTaskComplete(UpdateData updateData) {

        Utils.debugger.logDebug(TAG, "ParseXMLTask Complete, launch ValidatorTask");
        launchValidatorTask(updateData);
    }

    private void onValidatorTaskComplete(UpdateData result) {

        Utils.debugger.logDebug(TAG, "ValidatorTask Complete, launch DatabaseUpdateTask");
        launchDatabaseUpdate(result);
    }

    private void onDatabaseUpdateTaskComplete(DatabaseUpdateTask task) {
        Utils.debugger.logDebug(TAG, "DatabaseUpdateTask Complete, launch SettingsUpdateTask");
        launchSettingsUpdate(task.getUpdateData());
    }
    private void onSettingsUpdateTaskComplete(SettingsUpdateTask task) {

        Utils.debugger.logDebug(TAG, "Settings UpdateTask Complete: Launch DownloadImagesTask");
        launchDownloadImages();
        
    }
    
    private void onLaunchDownloadImagesTaskComplete(DownloadImagesTask task) {

        Utils.debugger.logDebug(TAG, "Download images UpdateTask Complete: Launch UpdateTaskComplete");
        onUpdateTaskComplete();
    }

    public void onUpdateTaskComplete() {

        Utils.debugger.logDebug(TAG, "UpdateTask Complete!");
        updateManagerSettings.commit();

       
            if(listener != null){
                listener.onUpdateComplete();
            }
      
        
    }

    /* ************************* */
    /*       Failed tasks        */
    /* ************************* */

    private void onReadXMLTaskFailed(ReadXMLTask task, Exception e) {
        Utils.debugger.logDebug(TAG, "ReadXMLTask Failed: " + e.getMessage());
        onUpdateTaskFailed(e);
    }

    private void onParseXMLTaskFailed(ParseXMLTask task, Exception e) {

        Utils.debugger.logDebug(TAG, "ParseXMLTask Failed: " + e.getMessage());
        onUpdateTaskFailed(e);
    }

    private void onValidatorTaskFailed(UpdateDataValidatorTask task, Exception e) {

        Utils.debugger.logDebug(TAG, "ValidatorTask Failed: " + e.getMessage());
        onUpdateTaskFailed(e);
    }

    private void onDatabaseUpdateTaskFailed(DatabaseUpdateTask task, Exception e) {
        Utils.debugger.logDebug(TAG, "DatabaseUpdateTask Failed: " + e.getMessage());
        launchSettingsUpdate(task.getUpdateData());
    }

    private void onSettingsUpdateTaskFailed(SettingsUpdateTask task, Exception e) {

        Utils.debugger.logDebug(TAG, "Settings UpdateTask Failed: " + e.getMessage());
        onUpdateTaskFailed(e);
    }
    
    private void onLaunchDownloadImagesTaskFailed(DownloadImagesTask task, Exception e) {

        Utils.debugger.logDebug(TAG, "Download images UpdateTask Failed: " + e.getMessage());
        onUpdateTaskComplete();
    }

    public void onUpdateTaskFailed(Exception e) {
        updateManagerSettings.abordTransaction();
        Utils.debugger.logDebug(TAG, "UpdateTask Failed: " + e.getMessage());
        
//        if(e.getMessage()==UpdateDataValidatorTask.OLD_XML_FILE){
//            launchDownloadImages();
//        }
       
            if (listener != null)
                listener.onUpdateError();
   
    }

    /* ************************* */
    /*       Listeners methods   */
    /* ************************* */

    public void onComplete(Tasks task, Object result) {

        int taskId = task.getTaskId();

//        updateManagerSettings.commit();

        switch (taskId) {

            case Tasks.XML_READ_TASK_ID: {
                onReadXMLTaskComplete((InputStream) result);
            }
                break;

            case Tasks.PARSER_TASK_ID: {
                onParseXMLTaskComplete((UpdateData) result);
            }
                break;

            case Tasks.VALIDATOR_TASK_ID: {
                onValidatorTaskComplete((UpdateData) result);
            }
                break;

            case Tasks.UPDATE_DATABASE_TASK_ID: {
                onDatabaseUpdateTaskComplete((DatabaseUpdateTask) task);
            }
                break;

            case Tasks.SETTINGS_UPDATE_TASK_ID: {
                onSettingsUpdateTaskComplete((SettingsUpdateTask) task);
            }
                break;
                
            case Tasks.DOWNLOAD_IMAGE_TASK_ID: {
               onLaunchDownloadImagesTaskComplete((DownloadImagesTask)task);
            }
                break;

        }

    }

    public void onError(Tasks task, Exception exception) {

        int taskId = task.getTaskId();

//        updateManagerSettings.abordTransaction();

        switch (taskId) {

            case Tasks.XML_READ_TASK_ID: {
                onReadXMLTaskFailed((ReadXMLTask) task, exception);
            }
                break;

            case Tasks.PARSER_TASK_ID: {
                onParseXMLTaskFailed((ParseXMLTask) task, exception);
            }
                break;

            case Tasks.VALIDATOR_TASK_ID: {
                onValidatorTaskFailed((UpdateDataValidatorTask) task, exception);
            }
                break;

            case Tasks.UPDATE_DATABASE_TASK_ID: {
                onDatabaseUpdateTaskFailed((DatabaseUpdateTask) task, exception);
            }
                break;

            case Tasks.SETTINGS_UPDATE_TASK_ID: {
                onSettingsUpdateTaskFailed((SettingsUpdateTask) task, exception);
            }
                break;
                
            case Tasks.DOWNLOAD_IMAGE_TASK_ID: {
                onLaunchDownloadImagesTaskFailed((DownloadImagesTask)task, exception);
             }
                 break;
        }

    }



}
